﻿#define _CRT_SECURE_NO_WARNINGS 1


//删除并获得点数
//https://leetcode.cn/problems/delete-and-earn/description/
class Solution {
public:
    int deleteAndEarn(vector<int>& nums)
    {
        int arr[10001] = { 0 };
        for (auto n : nums) arr[n] += n;

        //创建dp
        vector<int> f(10001);
        auto g = f;
        //填表
        for (int i = 1; i < 10001; i++)
        {
            f[i] = g[i - 1] + arr[i];
            g[i] = max(f[i - 1], g[i - 1]);
        }
        return max(f[10000], g[10000]);
    }
};


//粉刷房⼦
//https://leetcode.cn/problems/JEj789/

class Solution {
public:
    int minCost(vector<vector<int>>& costs)
    {
        //创建dp
        int m = costs.size();
        vector<vector<int>> dp(m + 1, vector<int>(3));
        //填表
        for (int i = 1; i <= m; i++)
        {
            dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i - 1][0];
            dp[i][2] = min(dp[i - 1][1], dp[i - 1][0]) + costs[i - 1][2];
            dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1];
        }
        //返回
        int ret = INT_MAX;
        for (int i = 0; i <= 2; i++)
        {
            ret = min(ret, dp[m][i]);
        }
        return ret;
    }
};

//https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/
//买卖股票的最佳时机含冷冻期

class Solution {
public:
    int maxProfit(vector<int>& p)
    {
        //创建dp
        int m = p.size();
        vector<vector<int>> dp(m, vector<int>(3));
        dp[0][0] = -p[0];
        //填表
        for (int i = 1; i < m; i++)
        {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - p[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]);
            dp[i][2] = dp[i - 1][0] + p[i];
        }
        return max(dp[m - 1][1], dp[m - 1][2]);
    }
};



//https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
//

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee)
    {
        int n = prices.size();
        vector<int> f(n);
        auto g = f;
        //初始化
        f[0] = -prices[0];
        for (int i = 1; i < n; i++)
        {
            f[i] = max(f[i - 1], g[i - 1] - prices[i]);
            g[i] = max(g[i - 1], f[i - 1] + prices[i] - fee);
        }
        //return max(f[n - 1],g[n - 1]);
        return g[n - 1];
    }
};

//https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/description/
class Solution {
public:
    int maxProfit(vector<int>& prices)
    {
        int n = prices.size();
        int c = 3;
        const int MIN = -0x3f3f3f3f;
        vector<vector<int>> f(n, vector<int>(c, MIN));
        auto g = f;
        //初始化
        f[0][0] = -prices[0], g[0][0] = 0;
        //填表
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j < c; j++)
            {
                f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);
                g[i][j] = g[i - 1][j];
                if (j - 1 >= 0)
                    g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + prices[i]);
            }
        }
        int ret = MIN;
        for (int i = 0; i < c; i++)
        {
            ret = max(ret, g[n - 1][i]);
        }
        return ret;

    }
};


//https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/

class Solution {
public:
    int maxProfit(int k, vector<int>& prices)
    {
        int n = prices.size();
        const int MIN = -0x3f3f3f3f;
        //创建dp
        vector<vector<int>> f(n, vector<int>(k + 1, MIN));
        auto g = f;
        //初始化
        f[0][0] = -prices[0], g[0][0] = 0;
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j <= k; j++)
            {
                f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);
                g[i][j] = g[i - 1][j];
                if (j - 1 >= 0) g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + prices[i]);
            }
        }
        int ret = MIN;
        for (int i = 0; i <= k; i++)
        {
            ret = max(ret, g[n - 1][i]);
        }
        return ret;
    }
};